package com.gomoku.service;

import com.gomoku.model.Board;
import com.gomoku.model.Move;
import com.gomoku.utils.MCTNode;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class AIService_MCTS {
    private static  int SIMULATION_COUNT = 250;
    private static  final double EXPLORATION_PARAMETER = 1.41; // UCB1 参数
    private static  int MAX_CHILDREN = 4; // 限制每个节点的展开子节点数量
    private static  int MAX_DEPTH = 10; // 添加最大搜索深度限制

    // 增加评分权重
    private static final int FIVE_IN_ROW = 100000;  // 连五
    private static final int OPEN_FOUR = 20000;     // 活四
    private static final int BLOCKED_FOUR = 8000;   // 冲四
    private static final int OPEN_THREE = 3000;     // 活三
    private static final int BLOCKED_THREE = 1200;   // 眠三
    private static final int OPEN_TWO = 200;        // 活二
    private static final int BLOCKED_TWO = 50;      // 眠二

    public static void setDifficulty(int level) {
        switch (level) {
            case 2: // Easy
                SIMULATION_COUNT = 50;
                MAX_DEPTH = 3;
                MAX_CHILDREN = 2;
                break;
            case 4: // Medium
                SIMULATION_COUNT = 250;
                MAX_DEPTH = 4;
                MAX_CHILDREN = 10;
                break;
            case 8: // Hard
                SIMULATION_COUNT = 400;
                MAX_DEPTH = 10;
                MAX_CHILDREN = 15;
                break;
        }
    }



    public Move calculateNextMove(Board board) {
        MCTNode root = new MCTNode(board, null, null);
        int aiPlayer = Board.AI;
        for (int i = 0; i < SIMULATION_COUNT; i++) {
            //必须选择子节点
            MCTNode selectedNode = select(root);
            //扩展节点，产生新的节点
            if (!isTerminal(selectedNode.state) && selectedNode.depth < MAX_DEPTH) {
                expand(selectedNode, aiPlayer);
            }
            //随机模拟，从当前状态开始，模拟一场游戏的结束
            double result = simulate(selectedNode, aiPlayer);
            //反向传播
            backpropagate(selectedNode, result);
        }
        //System.out.println("111111111111");
        // 从根节点选择访问次数最多的子节点作为最佳动作
        return root.children.stream()
                .max(Comparator.comparingInt(n -> n.visits))
                .map(n -> n.move)
                .orElse(null);
    }

    private MCTNode select(MCTNode node) {
        while (!node.children.isEmpty()) {
            node = node.children.stream()
                    .max(Comparator.comparingDouble(this::ucb1))
                    .orElse(null);
        }
        return node;
    }

    private void expand(MCTNode node, int aiPlayer) {
        List<Move> moves = generateMoves(node.state, aiPlayer);
        moves.sort(Comparator.comparingInt(move -> -evaluateMove(node.state, move, aiPlayer)));

        // 只选择前 MAX_CHILDREN 个最佳动作
        moves = moves.subList(0, Math.min(MAX_CHILDREN, moves.size()));

        for (Move move : moves) {
            Board newState = node.state.copy();
            newState.makeMove(move.getRow(), move.getCol(), aiPlayer == Board.AI);

            // 提前剪枝：如果能阻止对手直接获胜
            if (isDefensiveMove(node.state, move, aiPlayer)) {
                node.children.add(new MCTNode(newState, node, move, 1.0, 1));
                return;
            }

            if (newState.checkWin(move.getRow(), move.getCol())) {
                node.children.add(new MCTNode(newState, node, move, 1.0, 1));
                return; // 提前剪枝，直接返回胜利结果
            }

            node.children.add(new MCTNode(newState, node, move));
        }
    }

    private double simulate(MCTNode node, int aiPlayer) {
        Board simulatedBoard = node.state.copy();
        int currentPlayer = aiPlayer;
        int depth = 0;
        
        while (!isTerminal(simulatedBoard) && depth < MAX_DEPTH) {
            List<Move> moves = generateMoves(simulatedBoard, currentPlayer);
            if (moves.isEmpty()) break;

            // 在模拟中也要考虑防守
            Move move;
            if (depth < 3) { // 前几步使用启发式选择
                move = selectHeuristicMove(simulatedBoard, moves, currentPlayer);
            } else { // 后面的步骤随机选择
                int maxMoves = Math.min(3, moves.size());
                move = moves.get(new Random().nextInt(maxMoves));
            }
            
            simulatedBoard.makeMove(move.getRow(), move.getCol(), currentPlayer == Board.AI);
            currentPlayer = 3 - currentPlayer;
            depth++;
        }
        
        return evaluate(simulatedBoard, aiPlayer);
    }

    private void backpropagate(MCTNode node, double result) {
        while (node != null) {
            node.visits++;
            node.wins += result;
            node = node.parent;
        }
    }

    private double ucb1(MCTNode node) {
        if (node.visits == 0) return Double.MAX_VALUE;
        return node.wins / node.visits + EXPLORATION_PARAMETER * Math.sqrt(Math.log(node.parent.visits) / node.visits);
    }

    private boolean isTerminal(Board board) {
        return board.isFull() || board.checkWinCondition();
    }

    private double evaluate(Board board, int aiPlayer) {
        if (board.checkWinConditionForPlayer(aiPlayer)) return 1.0;
        if (board.checkWinConditionForPlayer(3 - aiPlayer)) return 0.0;
        return 0.5; // 平局或未知情况
    }

    // 修改评分权重，进一步提高防守权重
    private int evaluateBoard(Board board, int player) {
        int score = 0;
        int opponent = 3 - player;
        int[][] grid = board.getGrid();

        // 评估所有方向
        for (int i = 0; i < Board.BOARD_SIZE; i++) {
            for (int j = 0; j < Board.BOARD_SIZE; j++) {
                if (grid[i][j] != 0) {
                    if (grid[i][j] == player) {
                        score += evaluatePoint(grid, i, j, player);
                        //System.out.println("进攻: " + score);
                    } else if (grid[i][j] == opponent) {
                        // 大幅提高防守权重
                        score -= evaluatePoint(grid, i, j, opponent);
                        //System.out.println("防守: " + score);
                    }
                }
            }
        }
        return score;
    }

    // 评估某个点的威胁程度
    private int evaluatePoint(int[][] grid, int row, int col, int player) {
        int score = 0;
        // 检查八个方向
        int[][] directions = {{1,0}, {0,1}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            score += evaluateDirection(grid, row, col, dir[0], dir[1], player);
        }
        return score;
    }

    // 修改evaluateDirection方法，增加对斜线方向的重视
    private int evaluateDirection(int[][] grid, int row, int col, int dRow, int dCol, int player) {
        int count = 1;
        int openEnds = 0;
        int blocked = 0;
        
        // 向正方向检查
        int r = row + dRow;
        int c = col + dCol;
        int consecutiveCount = 1;
        while (isValidPosition(r, c)) {
            if (grid[r][c] == player) {
                count++;
                consecutiveCount++;
                r += dRow;
                c += dCol;
            } else if (grid[r][c] == 0) {
                openEnds++;
                break;
            } else {
                blocked++;
                break;
            }
        }

        // 向反方向检查
        r = row - dRow;
        c = col - dCol;
        while (isValidPosition(r, c)) {
            if (grid[r][c] == player) {
                count++;
                consecutiveCount++;
                r -= dRow;
                c -= dCol;
            } else if (grid[r][c] == 0) {
                openEnds++;
                break;
            } else {
                blocked++;
                break;
            }
        }

        // 对斜线方向的连续棋子给予额外奖励
        int baseScore = calculatePatternScore(count, openEnds);
        return baseScore;
    }

    // 计算棋型分数
    private int calculatePatternScore(int count, int openEnds) {
        if (count >= 5) return FIVE_IN_ROW;
        if (count == 4) {
            if (openEnds == 2) return OPEN_FOUR;
            if (openEnds == 1) return BLOCKED_FOUR;
        }
        if (count == 3) {
            if (openEnds == 2) return OPEN_THREE;
            if (openEnds == 1) return BLOCKED_THREE;
        }
        if (count == 2) {
            if (openEnds == 2) return OPEN_TWO;
            if (openEnds == 1) return BLOCKED_TWO;
        }
        return 0;
    }

    // 优化移动生成策略
    private List<Move> generateMoves(Board board, int player) {
        List<Move> moves = new ArrayList<>();
        int[][] grid = board.getGrid();
        
        // 只考虑已有棋子周围2格范围内的空位
        for (int i = 0; i < Board.BOARD_SIZE; i++) {
            for (int j = 0; j < Board.BOARD_SIZE; j++) {
                if (grid[i][j] == 0 && hasNeighbor(grid, i, j, 2)) {
                    moves.add(new Move(i, j));
                }
            }
        }
        
        // 只返回评分最高的前10个移动
        if (moves.size() > 10) {
            moves.sort((a, b) -> Integer.compare(
                evaluateMove(board, b, player),
                evaluateMove(board, a, player)
            ));
            return moves.subList(0, 10);
        }
        
        return moves;
    }

    // 优化邻居检查
    private boolean hasNeighbor(int[][] grid, int row, int col, int distance) {
        for (int i = Math.max(0, row - distance); i <= Math.min(Board.BOARD_SIZE - 1, row + distance); i++) {
            for (int j = Math.max(0, col - distance); j <= Math.min(Board.BOARD_SIZE - 1, col + distance); j++) {
                if (grid[i][j] != 0) {
                    return true;
                }
            }
        }
        return false;
    }

    // 修改evaluateMove方法，增加防守权重
    private int evaluateMove(Board board, Move move, int player) {
        Board newBoard = board.copy();
        newBoard.makeMove(move.getRow(), move.getCol(), player == Board.AI);
        
        // 进攻得分
        int attackScore = evaluateBoard(newBoard, player);
        
        // 防守得分（评估如果对手在这个位置下棋的威胁）
        Board defenseBoard = board.copy();
        defenseBoard.makeMove(move.getRow(), move.getCol(), player != Board.AI);
        int defenseScore = evaluateBoard(defenseBoard, 3 - player) ;

        // 普通情况下的评分
        return attackScore + defenseScore;
    }

    private boolean isValidPosition(int row, int col) {
        return row >= 0 && row < Board.BOARD_SIZE && col >= 0 && col < Board.BOARD_SIZE;
    }

    // 优化启发式移动选择
    private Move selectHeuristicMove(Board board, List<Move> moves, int player) {
        Move bestMove = null;
        int bestScore = Integer.MIN_VALUE;
        
        for (Move move : moves) {
            int score = evaluateMove(board, move, player);
             //如果是防守位置，增加权重
            if (isDefensiveMove(board, move, player)) {
                score += OPEN_FOUR;
            }
            if (score > bestScore) {
                bestScore = score;
                bestMove = move;
            }
        }
        return bestMove != null ? bestMove : moves.get(0);
    }

    // 新增：判断是否是防守位置
    private boolean isDefensiveMove(Board board, Move move, int player) {
        int opponent = 3 - player;
        Board tempBoard = board.copy();
        tempBoard.makeMove(move.getRow(), move.getCol(), opponent == Board.AI);

        // 检查这个位置是否能阻止对手连线
        int opponentScore = evaluatePoint(tempBoard.getGrid(), move.getRow(), move.getCol(), opponent);
        return opponentScore >= OPEN_THREE; // 如果对手在这个位置能形成活三或更强的威胁
    }



}






